iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
自我挑戰組

玩程式新手村 – C和Python系列 第 28

第28天 - C 和 Python的作用範圍(scope)

  • 分享至 

  • xImage
  •  

如何在函式內直接改變全域變數?

不經由函式參數而直接在函式內使用全域變數 (global variable),在絕大部分的情況下都不建議這種方式。但可藉著這個問題來說明全域變數,更進一步的解釋什麼是作用範圍 (scope)。

  • C 語言的全域變數:

    • 在所有函式或程式碼區塊外宣告或直接定義的變數,稱為全域變數 (global variable)。在程式的所有位置 (例如:函式內,或 for迴圈區塊內) 都可以使用或改變這變數,稱這變數有全域範圍 (global scope)。
    • 全域變數通常是放在程式碼的前面或標頭檔案 .h 內宣告。
    • 如果全域變數定義在檔案 file1.c
      int myGlobal = 10;
      在另一檔案 file2.c 使用或改變這全域變數前,要用 extern 先宣告。
      extern int myGlobal;

    另外說明:函式的使用也同樣要遵循這規則,在另一檔案使用函式前,要用 extern 先宣告。但如果函式已經在標頭檔案 .h 內宣告,而這程式碼檔案 有 #include 標頭檔案,就不需要另外用 extern 宣告,這也是通常建議的方法。

    舉例說明:

    #include <stdio.h>
    
    int myGlobal = 10; // 全域變數
    
    void myFunc() {
        myGlobal += 3;
        printf("在函式內, myGlobal = %d\n", myGlobal);
    }
    
    int main() {
        printf("執行函式前, myGlobal = %d\n", myGlobal);
        myFunc();
        printf("執行函式後, myGlobal = %d\n", myGlobal);
        return 0;
    }
    
    /* 輸出:
    執行函式前, myGlobal = 10
    在函式內, myGlobal = 13  
    執行函式後, myGlobal = 13
    */
    
  • Python 的全域變數:

    • 在函式以外宣告的變數稱為全域變數 (global variable),它的作用範圍 (scope) 為整個程式碼。在程式的所有位置都可以使用這變數,但不建議在函式內直接使用全域變數。

    • 如果在函式內要改變全域變數的值,要先用 global 宣告這變數。

      my_global = 10          # my_global 是 全域變數
      for num in range(3):    # num 也是 全域變數
          print(num, end=' ')  
      
      def main():
          my_var = 5
      
          my_function()
          print("全域變數: ", my_global)    # 全域變數:  13
          # print(f"區域變數: {my_local}")  # NameError. 不可使用my_function()的區域變數
      
          print("在for迴圈內, num =", end=' ')
          for num in range(my_var):  # Pylint, W0621:redefined-outer-name. (和函式外面的全域變數 num 同名)
              print(num, end=' ')          
          print(f"\n在for迴圈外, num = {num}")    # 在for迴圈外, num = 4  
      
      def my_function():
          my_local = 3
          global my_global  # 如要改變全域變數的值,就要用 global 宣告
      
          my_global += 3    # 如沒用 global 宣告, 會產生錯誤 UnboundLocalError
          print(f"在函式內, my_global = {my_global}")  # 在函式內, my_global = 13
          print(f"在函式內, num = {num}")              # 在函式內, num = 2, (這是全域變數)
          # print(f"在函式內, my_var = {my_var}")  # NameError. 不可使用main()的區域變數
      
      if __name__ == '__main__':
          main()
      

作用範圍 (scope)

前面我們有談到 全域變數 (global variable) 和 全域範圍 (global scope),接著要更完整介紹整個作用範圍 (scope) 。

作用範圍 (scope) 指的是變數、常數、函式或其他定義語句可以「被存取得到」的範圍。

  • C 語言的作用範圍

    • C 語言的區塊 (block) 就是任何以大括號 { .... } 包起來的區域,例如:函式區塊、 if 區塊、for 區塊、while 區塊等

    • C 語言的區域變數 (local variable) 是指 函式內或 區塊內 宣告的變數,或是參數列的參數。
      例如:

      for(int i = 0; i < 100; i++) { int num; ... }

      區域變數 inum 作用範圍只在區塊內。而在迴圈執行完畢後,就不再有效。

    • 在C語言中,如何在函式執行結束後,仍可以保留區域變數的結果?

      只要在區域變數宣告前加上 static 成為靜態變數 (static variable),它只初始化一次,函式執行結束後,靜態變數的值也會被保留,下次再執行函式時,靜態變數將保持上一次的值。
      例如:

      #include <stdio.h>
      
      void myFunc() {
          static int count = 0;  // static variable
          count += 3;
          printf("count = %d\n", count);
      }
      
      int main() {
          myFunc();   // count = 3
          myFunc();   // count = 6
          myFunc();   // count = 9
          return 0;
      }
      
  • Python的作用範圍

    • Python 定義了四種作用範圍,從內而外分別是區域 (local)、閉包 (enclosing) 、全域 (global) 和 內置預設 (built-in) 。
      • 閉包範圍 (enclosing scope) 是一特殊作用範圍,只存在前篇文章介紹的巢狀函式
      • 內置預設範圍 (built-in scope) 簡單的說是指內建的函式 (如 print(), len()) 、內建的型態 (如 int, list, bool) 等內建物件,不需要 import,在程式碼任何位置都可使用。
    • Python 的區域變數 (local variable) 是指 函式內的變數,或是函式參數。
    • 迴圈或條件判斷區塊內定義的變數在區塊外仍然可用。這和 C 語言不一樣。
    for i in range(3):
        a = i + 3
        print(i)
    
    print(f"在for迴圈外, i = {i}")  # 在for迴圈外, i = 2
    print(f"在for迴圈外, a = {a}")  # 在for迴圈外, a = 5
    
    • 最後,用這例子說明類別 (class) 的變數作用範圍:
    class A_class:
        x = 6
    
        def output(self, x):  # 這是較好的方式
            print(x)        # 30, x 是參數
            print(self.x)   # 6, self.x 是 類別變數
    
        def test(self):  # 不建議的方式
            print(x)       # 13, x 是全域變數, 如沒定義全域變數 x = 13, 則會產生錯誤 NameError
            print(self.x)  # 6, self.x 是 類別變數        
    
    
    def my_func():
        x = 30
        a = A_class()
        a.output(x)     # 將區域變數 x 設為參數
        a.test()
    
     x = 13
    my_func()
    

上一篇
第27天 - C 和 Python函式的對抗 (二)
下一篇
第29天 - Python 小露身手 (彩蛋)
系列文
玩程式新手村 – C和Python30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言